package cn.yuhe.basic.service.impl;

import cn.yuhe.basic.constants.BaseConstants;
import cn.yuhe.basic.dto.SmsCodeDto;
import cn.yuhe.basic.exception.BusinessException;
import cn.yuhe.basic.service.IVerifyCodeService;
import cn.yuhe.basic.utils.StrUtils;
import cn.yuhe.basic.utils.VerifyCodeUtils;
import cn.yuhe.user.domain.User;
import cn.yuhe.user.mapper.UserMapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;


    @Override
    public String getImageCode(String imageCodeKey) {
        // 1.判断参数是否为空
        if (StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("参数不能为空，请传递正确参数！");
        }
        // 2.获取到随机4位字符串
        String imageCode = StrUtils.getComplexRandomString(4);
        // 3.使用工具类生成Base64图形验证码字符串
        String imageBase64Str = VerifyCodeUtils.VerifyCode(100, 30, imageCode);
        // 4.根据key、value保存到Redis中，并设置三分钟有效
        redisTemplate.opsForValue().set(imageCodeKey, imageCode, 5, TimeUnit.MINUTES);
        return imageBase64Str;
    }

    /**
    * @Title: smsCode
    * @Description: 发发送短信验证码
    * @Author: Mr.Qiu
    * @Version: 1.0
    * @Date:  2022/7/6 16:00
    * @Parameters: [smsCodeDto]
    * @Return void
    */
    @Override
    public void smsCode(SmsCodeDto smsCodeDto) {
        // 1.获取电子邮箱
        String email = smsCodeDto.getEmail();
        // 1.2,获取电话
        String phone = smsCodeDto.getPhone();
        // 1.3获取状态类型
        String type = smsCodeDto.getType();

        // 2,将邮箱和电话放入map中方法中方便判断
        HashMap<String , String> emailOrphone = new HashMap<>();
        emailOrphone.put("email",email);
        emailOrphone.put("phone",phone);

        // h1,判断参数是否为空
        if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(email)) {
            throw new BusinessException("参数不能为空！");
        }

        // h2,根据前端给type赋值，判断是那种业务
        if ("register".equals(type)){ // 注册业务
            // 判断图形码是否正确
            captcha(smsCodeDto);
            // 判断用户是否注册
            isRedisTemplate(emailOrphone);
            // 拼接注册业务键
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_KEY,emailOrphone);
        } else if ("binder".equals(type)){ // 微信绑定业务,发送短信验证码
            // 拼接绑定食物键
            if (StringUtils.isEmpty(type)){
                throw new BusinessException("参数不能为空！");
            }
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_KEY,emailOrphone);

        }



        // 3,根据电话查数据库判断用户是否已经注册如果已经注册提醒用户
        User user;
        if (StringUtils.isEmpty(phone)){
            user = userMapper.loadByPhone2(email);
        } else {
            user = userMapper.loadByPhone(phone);
        }
        if (user != null){
            throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
        }

    }


    public void sendCode(String businessKey,HashMap emailOrphone){
        //  4，根据电话号码拼接业务键，redis获取对应value值，判断是否纯在
        String email = (String)emailOrphone.get("email");
        String phone = (String)emailOrphone.get("phone");

        String phoneCodeKey = "";
        if (StringUtils.isEmpty(email)){
            phoneCodeKey = businessKey + phone;
        } else {
            phoneCodeKey = businessKey + email;
        }
        Object phoneCodeValue  = redisTemplate.opsForValue().get(phoneCodeKey);
        // 定义一个空字符串，专门用来接受验证码
        String phoneCode = "";
        if (phoneCodeValue == null) { // 不存在
            // 1,生成新的随机验证码，并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        } else { // 存在
            // 切割value得到的时间戳，跟现在的时间做减法，如果小于一分钟的毫秒数抛出异常
            String[]  phoneCodeValueTmp =phoneCodeValue.toString().split(":");
            // 将存入的时间戳,转换为long类型
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            long nowTime = System.currentTimeMillis();
            // 判断时间戳
            if (nowTime - oldTime < 1*60*1000) {
                throw new BusinessException("请一分钟之后再获取！");
            }
            // 将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        // 5,通过业务键+phone作为key，验证码加时间戳作为value，存入redis，设置三分钟有效
        String phoneCodeRedis  = System.currentTimeMillis()+ ":" + phoneCode;
        System.out.println("前面的kry="+phoneCodeKey);
        System.out.println("前面的v="+phoneCodeRedis);
        redisTemplate.opsForValue().set(phoneCodeKey,phoneCodeRedis,3,TimeUnit.MINUTES);
        // 6,发送短信验证吗

        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);
    }

    // 判断图形验证码
    public void captcha(SmsCodeDto smsCodeDto){
        // 获取图形验证码的value
        String imageCodeValue = smsCodeDto.getImageCodeValue();
        // 1,获取图形验证码的key
        String imageCodeKey = smsCodeDto.getImageCodeKey();

        // 2,判断参数是否为空
        if (StringUtils.isEmpty(imageCodeValue) || StringUtils.isEmpty(imageCodeKey)) {
            throw new BusinessException("参数不能为空！");
        }

        // 3,在上面图片验证码赋了值的，判断图形验证码是否正确及存在
        Object imageCodeValueTmp  = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码过期，请重新获取！");
        }
        // 忽略大小写判断用户输入的验证码和存入key的验证码是否一样
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)) {
            throw new BusinessException("验证码错误，请重新输入！");
        }
    }


    // 用户是否注册
    public void isRedisTemplate(HashMap emailOrphone){

        String phone = (String)emailOrphone.get("phone");
        String email = (String)emailOrphone.get("email");
        // 3,根据电话查数据库判断用户是否已经注册如果已经注册提醒用户
        User user;
        if (StringUtils.isEmpty(phone)){
            user = userMapper.loadByPhone2(email);
        } else {
            user = userMapper.loadByPhone(phone);
        }
        if (user != null){
            throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
        }
    }
}
